#pragma once
#include <string>
#include <vector>
#include <cmath>
#include <chrono>
#include <torch/torch.h>

/**
 * @namespace Utils
 * @brief 提供电离层建模程序中常用的工具函数
 */
namespace Utils {
    // 常量定义
    constexpr double PI = 3.14159265358979323846;
    constexpr double DEG2RAD = PI / 180.0;
    constexpr double RAD2DEG = 180.0 / PI;
    constexpr double LIGHT_SPEED = 299792458.0;      // 光速(m/s)
    constexpr double EARTH_RADIUS = 6371.0;          // 地球平均半径(km)
    constexpr double TECU_FACTOR = 40.3e16;          // 1 TECU = 10^16 electrons/m^2
    
    /**
     * @struct GPSTime
     * @brief GPS时间结构体
     */
    struct GPSTime {
        int week;                // GPS周
        double secondsOfWeek;    // 周内秒
    };
    
    /**
     * @struct YMDTime
     * @brief 年月日时间结构体
     */
    struct YMDTime {
        int year;
        int month;
        int day;
        int hour;
        int minute;
        double second;
    };
    
    /**
     * @brief 获取当前时间的年月日时分秒
     * @return YMDTime结构体
     */
    YMDTime getCurrentTime();
    
    /**
     * @brief 将年月日时间转换为GPS时间
     * @param time 年月日时间
     * @return GPS时间
     */
    GPSTime ymdToGPSTime(const YMDTime& time);
    
    /**
     * @brief 将GPS时间转换为年月日时间
     * @param gpsTime GPS时间
     * @return 年月日时间
     */
    YMDTime gpsTimeToYMD(const GPSTime& gpsTime);
    
    /**
     * @brief 计算电离层映射函数
     * @param elevation 高度角(度)
     * @param ionoHeight 电离层等效高度(km)
     * @return 映射函数值
     */
    double calculateMappingFunction(double elevation, double ionoHeight = 350.0);
    
    /**
     * @brief 计算电离层穿刺点(IPP)
     * @param stationLat 测站纬度(度)
     * @param stationLon 测站经度(度)
     * @param elevation 高度角(度)
     * @param azimuth 方位角(度)
     * @param ionoHeight 电离层等效高度(km)
     * @return [ippLat, ippLon] 穿刺点纬度和经度(度)
     */
    std::vector<double> calculateIPP(double stationLat, double stationLon, 
                                    double elevation, double azimuth, 
                                    double ionoHeight = 350.0);
    
    /**
     * @brief 计算两个GPS时间之间的秒数差
     * @param t1 第一个GPS时间
     * @param t2 第二个GPS时间
     * @return 时间差(秒)
     */
    double timeDifference(const GPSTime& t1, const GPSTime& t2);
    
    /**
     * @brief 计算归一化的勒让德多项式
     * @param n 阶数
     * @param m 级数
     * @param x 自变量(-1到1之间)
     * @return 归一化勒让德多项式值
     */
    double normalizedLegendre(int n, int m, double x);
    
    /**
     * @brief 将VTEC张量保存为CSV格式
     * @param vtecGrid VTEC网格张量
     * @param filename 输出文件名
     * @param latStart 起始纬度(度)
     * @param latStep 纬度步长(度)
     * @param lonStart 起始经度(度)
     * @param lonStep 经度步长(度)
     * @return 是否成功写入
     */
    bool saveVTECGridToCSV(const torch::Tensor& vtecGrid, const std::string& filename,
                          double latStart = 90.0, double latStep = 2.0,
                          double lonStart = 0.0, double lonStep = 2.0);
    
    /**
     * @brief 打印系统信息
     */
    void printSystemInfo();
    
    /**
     * @brief 检查文件是否存在
     * @param filename 文件名
     * @return 是否存在
     */
    bool fileExists(const std::string& filename);
    
    /**
     * @brief 创建目录（如果不存在）
     * @param path 目录路径
     * @return 是否成功
     */
    bool createDirectory(const std::string& path);
    
    /**
     * @brief 简单的字符串分割函数
     * @param s 要分割的字符串
     * @param delimiter 分隔符
     * @return 分割后的字符串向量
     */
    std::vector<std::string> split(const std::string& s, char delimiter);
    
    /**
     * @brief 去除字符串首尾空白字符
     * @param s 输入字符串
     * @return 去除空白后的字符串
     */
    std::string trim(const std::string& s);

    /**
     * @brief WGS-84椭球参数
     */
    constexpr double WGS84_A = 6378137.0;          // 长半轴(m)
    constexpr double WGS84_F = 1.0/298.257223563;  // 扁率
    constexpr double WGS84_B = WGS84_A*(1.0-WGS84_F); // 短半轴(m)
    constexpr double WGS84_E2 = 2*WGS84_F-WGS84_F*WGS84_F; // 第一偏心率平方
    constexpr double WGS84_EP2 = WGS84_E2/(1.0-WGS84_E2);  // 第二偏心率平方

    /**
     * @brief 笛卡尔坐标转换为大地坐标(经纬高)
     * @param xyz 笛卡尔坐标[x,y,z](m)
     * @return [lat,lon,h] 纬度(度),经度(度),高度(m)
     */
    std::vector<double> xyzToBlh(const std::vector<double>& xyz);

    /**
     * @brief 笛卡尔坐标转换为大地坐标(经纬高) - 别名
     * @param ecef 笛卡尔坐标[x,y,z](m)
     * @return [lat,lon,h] 纬度(度),经度(度),高度(m)
     */
    std::vector<double> ecef2llh(const std::vector<double>& ecef);

    /**
     * @brief 大地坐标(经纬高)转换为笛卡尔坐标
     * @param blh 大地坐标[lat,lon,h] 纬度(度),经度(度),高度(m)
     * @return [x,y,z] 笛卡尔坐标(m)
     */
    std::vector<double> blhToXyz(const std::vector<double>& blh);

    /**
     * @brief 计算站心坐标系(ENU)的旋转矩阵
     * @param lat 站点纬度(度)
     * @param lon 站点经度(度)
     * @return 3x3旋转矩阵
     */
    std::vector<std::vector<double>> computeRotationMatrix(double lat, double lon);

    /**
     * @brief 计算ECEF坐标系中两点间的站心坐标(ENU)
     * @param refXyz 参考点ECEF坐标[x,y,z](m)
     * @param targetXyz 目标点ECEF坐标[x,y,z](m)
     * @param refBlh 参考点大地坐标[lat,lon,h](度,度,m)
     * @return [e,n,u] 东北天坐标(m)
     */
    std::vector<double> computeENU(const std::vector<double>& refXyz, 
                                  const std::vector<double>& targetXyz,
                                  const std::vector<double>& refBlh);

    /**
     * @brief 将年月日时分秒转换为GPS时间
     * @param year 年份
     * @param month 月份
     * @param day 日期
     * @param hour 小时
     * @param minute 分钟
     * @param second 秒
     * @return GPSTime结构体
     */
    GPSTime ymdhmsToGpst(int year, int month, int day, int hour, int minute, double second);
}; 